#include <Windows.h>
#include <fstream>
#include "SoundManager.h"
#include "DirectX.h"


SoundManager::SoundManager()
{
	ZeroMemory(&waveFormat, sizeof(waveFormat));
	ZeroMemory(&m_xa, sizeof(m_xa));
}
SoundManager::~SoundManager()
{

}

void SoundManager::Initialize()
{
#ifdef _DEBUG
	cout << "Initializing XAudio2...";
#endif


	// Create the XAudio Engine
	XAudio2Create( &pAudioEngine );

	// Enumerate the available devices
	UINT32 deviceCount;
	pAudioEngine->GetDeviceCount(&deviceCount);

	// Loop through the available devices to determine the most suitable device.
	XAUDIO2_DEVICE_DETAILS deviceDetails;
	int preferredDevice = 0;
	for (unsigned int i = 0; i < deviceCount; i++)
	{
		pAudioEngine->GetDeviceDetails(i,&deviceDetails);
		if (deviceDetails.OutputFormat.Format.nChannels > 2)
		{
			preferredDevice = i;
			break;
		}
	}

	pAudioEngine->CreateMasteringVoice( &pMasterVoice, XAUDIO2_DEFAULT_CHANNELS,
		XAUDIO2_DEFAULT_SAMPLERATE, 0, preferredDevice, nullptr );

	pAudioEngine->StartEngine();

	m_waveData = nullptr;

#ifdef _DEBUG
	cout << " Complete\n";
#endif
}

void SoundManager::Shutdown()
{
#ifdef _DEBUG
	cout << "Shutting Down XAudio2...";
#endif

	if(m_waveData)
		delete  m_waveData;
	m_waveData = nullptr;

	pAudioEngine->StopEngine();
	pAudioEngine->Release();

#ifdef _DEBUG
	cout << " Complete\n";
#endif
}

bool SoundManager::load(const char* szFile) 
{
	if(m_waveData)
		delete  m_waveData;
	m_waveData = nullptr;

	if(szFile == nullptr)
		return false;

	std::ifstream inFile(szFile, std::ios::binary | std::ios::in);
	if(inFile.bad())
		return false;

	DWORD dwChunkId = 0, dwFileSize = 0, dwChunkSize = 0, dwExtra = 0;

	//look for 'RIFF' chunk identifier
	inFile.seekg(0, std::ios::beg);
	inFile.read(reinterpret_cast<char*>(&dwChunkId), sizeof(dwChunkId));
	if(dwChunkId != 'FFIR')
	{
		inFile.close();
		return false;
	}
	inFile.seekg(4, std::ios::beg); //get file size
	inFile.read(reinterpret_cast<char*>(&dwFileSize), sizeof(dwFileSize));
	if(dwFileSize <= 16)
	{
		inFile.close();
		return false;
	}
	inFile.seekg(8, std::ios::beg); //get file format
	inFile.read(reinterpret_cast<char*>(&dwExtra), sizeof(dwExtra));
	if(dwExtra != 'EVAW')
	{
		inFile.close();
		return false;
	}

	//look for 'fmt ' chunk id
	bool bFilledFormat = false;
	for(unsigned int i = 12; i < dwFileSize; )
	{
		inFile.seekg(i, std::ios::beg);
		inFile.read(reinterpret_cast<char*>(&dwChunkId), sizeof(dwChunkId));
		inFile.seekg(i + 4, std::ios::beg);
		inFile.read(reinterpret_cast<char*>(&dwChunkSize), sizeof(dwChunkSize));
		if(dwChunkId == ' tmf')
		{
			inFile.seekg(i + 8, std::ios::beg);
			inFile.read(reinterpret_cast<char*>(&waveFormat), sizeof(waveFormat));
			bFilledFormat = true;
			break;
		}
		dwChunkSize += 8; //add offsets of the chunk id, and chunk size data entries
		dwChunkSize += 1;
		dwChunkSize &= 0xfffffffe; //guarantees WORD padding alignment
		i += dwChunkSize;
	}
	if(!bFilledFormat)
	{
		inFile.close();
		return false;
	}

	//look for 'data' chunk id
	bool bFilledData = false;
	for(unsigned int i = 12; i < dwFileSize; )
	{
		inFile.seekg(i, std::ios::beg);
		inFile.read(reinterpret_cast<char*>(&dwChunkId), sizeof(dwChunkId));
		inFile.seekg(i + 4, std::ios::beg);
		inFile.read(reinterpret_cast<char*>(&dwChunkSize), sizeof(dwChunkSize));
		if(dwChunkId == 'atad')
		{
			m_waveData = new BYTE[dwChunkSize];
			inFile.seekg(i + 8, std::ios::beg);
			inFile.read(reinterpret_cast<char*>(m_waveData), dwChunkSize);
			m_xa.AudioBytes = dwChunkSize;
			m_xa.pAudioData = m_waveData;
			m_xa.PlayBegin = 0;
			m_xa.PlayLength = 0;
			m_xa.LoopBegin = 1;
			bFilledData = true;
			break;
		}
		dwChunkSize += 8; //add offsets of the chunk id, and chunk size data entries
		dwChunkSize += 1;
		dwChunkSize &= 0xfffffffe; //guarantees WORD padding alignment
		i += dwChunkSize;
	}
	if(!bFilledData)
	{
		inFile.close();
		return false;
	}

	inFile.close();



	///////////////////////
	//create the source voice, based on loaded wave format
	pAudioEngine->CreateSourceVoice( &pSourceVoice, &waveFormat );

	return true;
}

void SoundManager::Play()
{
	//Start consuming audio in the source voice
	pSourceVoice->Start();
	pSourceVoice->SubmitSourceBuffer( &m_xa );
}

SoundManager* SoundManager::getInstance()
{
	
	static SoundManager	instance;

	return &instance;
}

